package com.cloudlinkscm.base.authcenter.domain;

import com.cloudlinkscm.base.authcenter.model.PublicResource;
import com.cloudlinkscm.base.authcenter.model.Resource;
import com.cloudlinkscm.base.authcenter.model.TenantResource;
import com.cloudlinkscm.base.authcenter.model.bo.NodeAllResourceBO;
import com.cloudlinkscm.base.authcenter.model.dto.ResourceTree;
import com.cloudlinkscm.loms.utils.CollectionUtils;
import org.springframework.stereotype.Component;

import java.util.*;

/**
 * Created by sin on 2017/8/10.
 */
@Component
public class ResourceManager {


	///
	/// convert resource

	/**
	 * 转换 resource 数据结构
	 *
	 * <p>
	 *     将 {@link TenantResource} 和 {@link PublicResource} 转换成 resource
	 * </p>
	 *
	 * @param resources
	 * @return
	 */
	public List<Resource> convertResource(List<? extends Resource> resources) {
		List<Resource> convertResources = new ArrayList<>(resources.size());
		for (Resource resource : resources) {
			convertResources.add(resource);
		}
		return convertResources;
	}


	///
	/// node position


	/**
	 * 节点定位
	 *
	 * <p>
	 *     找出节点有多少 parent 节点、和 children 节点
	 * </p>
	 *
	 * @see #positionNodes
	 *
	 * @param allResource 节点数
	 * @param positionResources 需要定位的节点
	 * @return
	 */
	public List<NodeAllResourceBO> positionNodes(List<Resource> allResource, List<Resource> positionResources) {
		List<NodeAllResourceBO> result = new ArrayList<>(positionResources.size());
		for (Resource positionResource : positionResources) {
			result.add(positionNodes(allResource, positionResource));
		}
		return result;
	}

	/**
	 * 节点: 定位 单个
	 *
	 * @param allResource
	 * @param positionResource
	 * @param
	 * @return
	 */
	public NodeAllResourceBO positionNodes(List<Resource> allResource, Resource positionResource) {

		Map<String, Resource> resourceMap = CollectionUtils.buildMap(
				allResource, String.class, Resource.class, "id");

		Map<String, List<Resource>> pidResourceMultimap = CollectionUtils.buildMultimap(
				allResource, String.class, Resource.class, "pid");

		// 上下 查找节点
		Set<Resource> rootResource = new HashSet<>();
		Set<Resource> childrenResource = new HashSet<>();

		upFind(rootResource, childrenResource, resourceMap, positionResource);
		childrenResource.addAll(downFind(positionResource, pidResourceMultimap));

		// 合并 root 和 children 节点
		List<Resource> distributionResource = new ArrayList<>(
				rootResource.size() + childrenResource.size());
		distributionResource.addAll(rootResource);
		distributionResource.addAll(childrenResource);

		return new NodeAllResourceBO(positionResource, rootResource, childrenResource, distributionResource);
	}



	/**
	 * 向下查找
	 *
	 * <p>
	 *     已当前节点位置，向下查询。
	 *        children：返回本身
	 *        root 根节点：返回多有 children 节点
	 * </p>
	 *
	 * @param allResource
	 * @param positionResources
	 * @return
	 */
	public List<NodeAllResourceBO> downFind(List<Resource> allResource, List<Resource> positionResources) {
		List<NodeAllResourceBO> result = new ArrayList<>();
		for (Resource positionResource : positionResources) {
			result.add(downFind(allResource, positionResource));
		}
		return result;
	}


	public NodeAllResourceBO downFind(List<Resource> allResource, Resource positionResource) {
		Map<String, List<Resource>> pidResourceMultimap = CollectionUtils.buildMultimap(
				allResource, String.class, Resource.class, "pid");

		// 下 查找节点
		Set<Resource> childrenResource = new HashSet<>(downFind(positionResource, pidResourceMultimap));
		// 合并 root 和 children 节点
		return new NodeAllResourceBO(positionResource,
				Collections.EMPTY_SET, childrenResource, new ArrayList<>(childrenResource));
	}



	/**
	 * 向上查询
	 *
	 * <p>
	 *     已当前节点位置，向上查询。
	 *        children：返回 parent 节点、直到 root 节点
	 *        root 根节点：返回本身
	 * </p>
	 *
	 * @param allResource 以什么资源数去查找
	 * @param positionResources 需要查找的节点
	 * @return
	 */
	public NodeAllResourceBO upFind(List<Resource> allResource, Resource positionResources) {
		Map<String, Resource> resourceMap = CollectionUtils.buildMap(
				allResource, String.class, Resource.class, "id");

		// 上下 查找节点
		Set<Resource> rootResource = new HashSet<>();
		Set<Resource> childrenResource = new HashSet<>();

		// 向上
		upFind(rootResource, childrenResource, resourceMap, positionResources);

		// 合并 root 和 children 节点
		List<Resource> distributionResource = new ArrayList<>(
				rootResource.size() + childrenResource.size());
		distributionResource.addAll(rootResource);
		distributionResource.addAll(childrenResource);

		return new NodeAllResourceBO(positionResources, rootResource, childrenResource, distributionResource);
	}


	private void upFind(Set<Resource> rootResource,
		                  Set<Resource> childrenResource,
		                  Map<String, Resource> tenantResourceMap,
	                      Resource resource) {

		if (!tenantResourceMap.containsKey(resource.getPid())) {
			// root resource
			rootResource.add(resource);
		}
		else {
			Resource parentResource = tenantResourceMap.get(resource.getPid());
			// parent resource
			childrenResource.add(resource);
			// next find
			upFind(rootResource, childrenResource, tenantResourceMap, parentResource);
		}
	}



	/**
	 * 树节点：向下查找
	 *
	 * @param resource
	 * @param pidResourceMultimap
	 * @return
	 */
	private Set<Resource> downFind(Resource resource,
	                                   Map<String, List<Resource>> pidResourceMultimap ) {

		if (!pidResourceMultimap.containsKey(resource.getId())) {
			// null
			return Collections.EMPTY_SET;
		}

		Set<Resource> childrenResource = new HashSet<>(pidResourceMultimap.get(resource.getId()));
		Set<Resource> needAddResource = new HashSet<>();
		for (Resource nextResource : childrenResource) {

			Set<Resource> resultResources = downFind(nextResource, pidResourceMultimap);

			// java.util.ConcurrentModificationException
			for (Resource resultResource : resultResources) {
				if (!childrenResource.contains(resultResource)) {
					needAddResource.add(resultResource);
				}
			}
		}

		childrenResource.addAll(needAddResource);
		return childrenResource;
	}




	///
	/// build tree


	/**
	 * 构建一个 resourceTree
	 *
	 * @param resources
	 * @return
	 */
	public List<ResourceTree> buildResourceTree(List<Resource> resources) {

		if (CollectionUtils.isEmpty(resources)) {
			return Collections.EMPTY_LIST;
		}

		Map<String, List<Resource>> publicResourceMultimap = CollectionUtils.buildMultimap(
				resources, String.class, Resource.class, "pid");

		return recursiveTree(ResourceTree.TREE_ROOT, publicResourceMultimap);
	}


	/**
	 * 递归构建一棵树
	 *
	 * @param id
	 * @param resourceMultimap
	 * @return
	 */
	private List<ResourceTree> recursiveTree(String id, Map<String, List<Resource>> resourceMultimap) {

		if (!resourceMultimap.containsKey(id)) {
			return Collections.EMPTY_LIST;
		}

		List<Resource> resourceList = resourceMultimap.get(id);
		List<ResourceTree> childrenList = new ArrayList<>();
		for (Resource resource : resourceList) {
			ResourceTree<Resource> childrenTreeDTO = new ResourceTree<>();
			childrenTreeDTO.setTitle(resource.getResourceName());
			childrenTreeDTO.setData(resource);

			// 递归子节点
			if (resourceMultimap.containsKey(resource.getId())) {
				childrenTreeDTO.setChildren(recursiveTree(resource.getId(), resourceMultimap));
			}

			childrenList.add(childrenTreeDTO);
		}

		return childrenList;
	}


	///
	///


	/**
	 * 获取 root 节点
	 *
	 * @param resources
	 * @return
	 */
	public String rootNodeId(List<Resource> resources) {

		Map<String, List<Resource>> parentResourceMultimap = CollectionUtils.buildMultimap(
				resources, String.class, Resource.class, "pid");

		Map<String, Resource> resourceMap = CollectionUtils.buildMap(
				resources, String.class, Resource.class, "id");

		for (Map.Entry<String, List<Resource>> entry : parentResourceMultimap.entrySet()) {
			if (!resourceMap.containsKey(entry.getKey())) {
				// root
				return entry.getKey();
			}
		}

		return null;
	}


	///
	/// 去重


	/**
	 * 构建一个新的 resource
	 *
	 * <p>
	 *     去除重复节点、存在子节点保留 parent 节点
	 * </p>
	 *
	 * @param resourceTrees
	 * @param tenantResourceMap
	 * @return
	 */
	public List<Resource> buildNewResource(List<ResourceTree> resourceTrees,
	                                       Map<String, TenantResource> tenantResourceMap) {

		List<Resource> newResource = new ArrayList<>();
		for (ResourceTree<Resource> resourceTree : resourceTrees) {
			if (!org.springframework.util.CollectionUtils.isEmpty(resourceTree.getChildren())) {
				List<Resource> childrenResource = buildNewResource(resourceTree.getChildren(), tenantResourceMap);

				// 父节点是否含有子节点
				if(childrenResource.size() > 0) {
					newResource.add(resourceTree.getData());
					newResource.addAll(childrenResource);
				}
			}

			// 添加子节点
			if (!tenantResourceMap.containsKey(resourceTree.getData().getResourceKey())) {
				newResource.add(resourceTree.getData());
			}
		}
		return newResource;
	}
}
